package com.longtop.perform.ar.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

import com.longtop.framework.base.BaseService;
import com.longtop.framework.common.CacheUtil;
import com.longtop.framework.common.Constant;
import com.longtop.framework.security.BaseCheckedException;
import com.longtop.framework.security.SessionObject;
import com.longtop.framework.util.DateUtil;
import com.longtop.framework.util.ReflectUtil;
import com.longtop.framework.util.UniqueKeyUtil;
import com.longtop.perform.ar.model.TExeBackCalc;

public class AssignMasterService extends BaseService {

	public static final String BEAN_ID = "assignMasterService";

	public List queryMaster(String hql) {
		List list = queryAll(hql);
		return list;
	}

	/**
	 * 通用保存分配主表
	 * 
	 * @param changeMap
	 * @param sessionObject
	 *            用户对象
	 * @return 返回保存后的主表ID
	 * @throws BaseCheckedException
	 * @author SUN
	 */
	public String saveMaster(Map changeMap, SessionObject sessionObject) throws BaseCheckedException, Exception {

		// 删除主键列表、更新bean的列表、新增bean的列表
		List insertBeanList = (ArrayList) changeMap.get(Constant.INSERT_BEAN_LIST);
		List updateBeanList = (ArrayList) changeMap.get(Constant.UPDATE_BEAN_LIST);
		List deleteBeanList = (ArrayList) changeMap.get(Constant.DELETE_BEAN_LIST);
		Object entity;
		String assignId = "";
		Iterator iterator;
		// 批量插入记录
		if (insertBeanList.size() > 0) {
			iterator = insertBeanList.iterator();
			while (iterator.hasNext()) {
				entity = iterator.next();
				Date enddate = (Date) ReflectUtil.getFieldValue(entity, "endDate");
				Date startdate = (Date) ReflectUtil.getFieldValue(entity, "startDate");
				if (enddate.getTime() < startdate.getTime()) {
					throw new BaseCheckedException("新增失败，业绩分配开始时间应小于或等于结束时间!");
				}
				if (isAllocationLegal(entity, true))
					throw new BaseCheckedException("新增失败，业绩分配时间不允许存在交叉。");
				if (recalcDispose(entity, true))
					throw new BaseCheckedException("新增失败，业绩分配开始时间超过回算时间，不允许此操作。");
				super.save(entity);
				assignId = "" + ReflectUtil.getFieldValue(entity, "id");
			}
		}

		// 批量更新记录
		if (updateBeanList.size() > 0) {
			iterator = updateBeanList.iterator();
			while (iterator.hasNext()) {
				entity = iterator.next();
				Date enddate = (Date) ReflectUtil.getFieldValue(entity, "endDate");
				Date startdate = (Date) ReflectUtil.getFieldValue(entity, "startDate");
				if (enddate.getTime() < startdate.getTime()) {
					throw new BaseCheckedException("更新失败，业绩分配开始时间应小于或等于结束时间!");
				}
				if (isAllocationLegal(entity, false))
					throw new BaseCheckedException("更新失败，业绩分配时间不允许存在交叉。");
				if (recalcDispose(entity, false))
					throw new BaseCheckedException("更新失败，业绩分配开始时间超过回算时间，不允许此操作。");

				super.update(entity);

				// 更新相应字表时间
				String detailClassName = entity.getClass().getSimpleName()+"Mx";
				String detailfkId = "" + ReflectUtil.getFieldValue(entity, "id");
				String updateDatailHql = "update " + detailClassName + " set endDate = ? where fkId ='" + detailfkId + "'";
				super.batchUpdate(updateDatailHql, new Object[] { enddate });

			}
		}
		// 批量删除记录
		if (deleteBeanList.size() > 0) {
			iterator = deleteBeanList.iterator();
			while (iterator.hasNext()) {
				entity = iterator.next();
				if (recalcDispose(entity, true))
					throw new BaseCheckedException("删除失败，业绩分配开始时间超过回算时间，不允许此操作。");

				// 删除子表与主表记录
				String detailClassName = entity.getClass().getSimpleName()+"Mx";
				String detailfkId = "" + ReflectUtil.getFieldValue(entity, "id");
				String detailSql = "delete from " + detailClassName + " where fkId ='" + detailfkId + "'";

				this.batchUpdate(detailSql);

				super.delete(entity);
			}
		}
		return assignId;
	}

	/**
	 * 回算处理,新增时需要验证开始时间是否需要回算或是否超过回算时间
	 * 
	 * @param entity
	 * 
	 * @param isStartDate
	 *            参照时间是否是开始时间(更新主表记录时候，参照的是结束时间。)：true:startDate;false:endDate
	 * @return
	 * @throws ServiceException
	 * @author SUN
	 */
	public boolean recalcDispose(Object entity, boolean isStartDate) {
		boolean flag = false;
		String recalcDays = CacheUtil.getConfigValueById(Constant.CONFIG_RECALC_DAYS);
		String workDates = CacheUtil.getConfigValueById(Constant.CONFIG_WORK_DATE);
		int recalcDay = Integer.parseInt(recalcDays);
		Date workDate = DateUtil.parseDate2(workDates);
		Date recalcDate = null;
		// 获取传入的实体对应的数据库表名
//		String tableName = StringUtil.changeClassNameToTableName(entity.getClass());

		// 修改后的结束时间：
		Date newEndDate = (Date) ReflectUtil.getFieldValue(entity, "endDate");
		if (isStartDate) {
			recalcDate = (Date) ReflectUtil.getFieldValue(entity, "startDate");
		} else {
			String fkId = "" + ReflectUtil.getFieldValue(entity, "id");
			Map<String, Object> queryMap = new HashMap<String, Object>();
//			queryMap.put("masterTableName", tableName);
			queryMap.put("fkId", fkId);
			// 未修改前的结束时间：
			Date oldEndDate = (Date) this.queryForObjectByIbatis("arAssignSql.queryMasterEndDate", queryMap);
			if (oldEndDate.compareTo(newEndDate) > 0) {
				recalcDate = newEndDate;
			} else {
				recalcDate = oldEndDate;
			}
		}

		// 判断开始时间是否大于业务时间减去回算天数
		if (recalcDate.getTime() > (workDate.getTime() - 1000 * 3600 * 24 * recalcDay)) {
			// 判断开始时间是否大于业务时间
			if (recalcDate.getTime() > workDate.getTime()) {
			} else {
				// 回算
				TExeBackCalc aaRtTimeRecalcVo = new TExeBackCalc();
				aaRtTimeRecalcVo.setId(UniqueKeyUtil.getUuidKey());
				aaRtTimeRecalcVo.setLogDate(DateUtil.formatDate2(recalcDate));
				super.save(aaRtTimeRecalcVo);
			}
		} else {
			flag = true;
		}

		return flag;
	}

	/**
	 * 验证此 业绩分配是否合法及时间处理
	 * 
	 * @param entity
	 * @param isInsert
	 *            是否是新增
	 * @return
	 * @throws ServiceException
	 * @author SUN
	 */
	public boolean isAllocationLegal(Object entity, boolean isInsert) throws Exception {
		boolean flag = false;
		String className = entity.getClass().getSimpleName();
		Date startDate = (Date) ReflectUtil.getFieldValue(entity, "startDate");
		Date endDate = (Date) ReflectUtil.getFieldValue(entity, "endDate");
		String id = "" + ReflectUtil.getFieldValue(entity, "id");
		String resId = "" + ReflectUtil.getFieldValue(entity, "resId");

		String fitOrgId = "" + ReflectUtil.getFieldValue(entity, "fitOrgId");
		String fitProductId = "" + ReflectUtil.getFieldValue(entity, "fitProductId");

		String hqlselect = "from " + className + " where resId='" + resId + "'";
		if (!"".equals(id) && !"null".equals(id)) {
			hqlselect = hqlselect + " and id <> '" + id + "'";
		}
		if (!"".equals(fitOrgId) && !"null".equals(fitOrgId)) {
			hqlselect = hqlselect + " and fitOrgId='" + fitOrgId + "'";
		}
		if (!"".equals(fitProductId) && !"null".equals(fitProductId)) {
			hqlselect = hqlselect + " and fitProductId='" + fitProductId + "'";
		}

		// 时间是否交叉（即（小的小于等于大的，大的大于大的）或（大的大于等于小的，小的小于小的）） 交叉返回报错
		List list = this.queryAll(hqlselect);
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				Object oldBean = list.get(i);
				Date oldStartDate = (Date) ReflectUtil.getFieldValue(oldBean, "startDate");
				Date oldEndDate = (Date) ReflectUtil.getFieldValue(oldBean, "endDate");
				if ((oldEndDate.getTime() >= startDate.getTime() && (oldEndDate.getTime() < endDate.getTime())) || (oldStartDate.getTime() > startDate.getTime() && (oldStartDate.getTime() <= endDate.getTime()))) {
					flag = true;
					break;
				}
			}
			// 不交叉之后，验证是否包含于某段时间（即小的大于小的，大的小于大的），是的话则处理
			if (!flag && isInsert) {
				for (int i = 0; i < list.size(); i++) {
					Object oldBean = list.get(i);

					String oldId = ReflectUtil.getFieldValue(oldBean, "id").toString();
					Date oldStartDate = (Date) ReflectUtil.getFieldValue(oldBean, "startDate");
					Date oldEndDate = (Date) ReflectUtil.getFieldValue(oldBean, "endDate");
					if ((oldStartDate.getTime() <= startDate.getTime() && (oldEndDate.getTime() >= endDate.getTime()))) {
						// 处理1：小的到小的之间，时间差是否大于等于1，是操作
						if ((startDate.getTime() - oldStartDate.getTime()) >= 1000 * 3600 * 24) {
							operateAllocationDetail(oldBean, oldStartDate, new Date(startDate.getTime() - 1000 * 3600 * 24));
						}
						// 处理2：大的到大的之间，时间差是否大于等于1，是操作
						if ((oldEndDate.getTime() - endDate.getTime()) >= 1000 * 3600 * 24) {
							operateAllocationDetail(oldBean, new Date(endDate.getTime() + 1000 * 3600 * 24), oldEndDate);
						}
						// 删除原业绩分配和详情
						String detailClassName = className+"Mx";
						String sql = "delete from " + detailClassName + " where fkId ='" + oldId + "'";
						this.batchUpdate(sql);

						String hql = "delete from " + className + " where id ='" + oldId + "'";
						this.batchUpdate(hql);

					}
				}
			}

		}
		return flag;
	}

	/**
	 * 业绩分配及详情处理(业绩分配复制,详情复制)
	 * 
	 * @param oldEntity
	 * @param newStartDate
	 * @param newEndDate
	 * @throws ServiceException
	 */
	public void operateAllocationDetail(Object oldEntity, Date newStartDate, Date newEndDate) throws Exception {
		String className = oldEntity.getClass().getSimpleName();
		String detailClassName = className+"Mx";
		String oldId = ReflectUtil.getFieldValue(oldEntity, "id").toString();
		// 查出原有的业绩分配明细：
		List list = this.queryAll("from " + detailClassName + " where fkId='" + oldId + "'");

		Object newMasterEntity = new Object();
		newMasterEntity = BeanUtils.cloneBean(oldEntity);

		// 保存修改时间后的主表记录：
		ReflectUtil.setFieldValue(newMasterEntity, "startDate", Date.class, newStartDate);
		ReflectUtil.setFieldValue(newMasterEntity, "endDate", Date.class, newEndDate);
		ReflectUtil.setFieldValue(newMasterEntity, "id", String.class, null);

		super.save(newMasterEntity);

		String newId = ReflectUtil.getFieldValue(newMasterEntity, "id").toString();// 保存成功后新的主表ID；
		for (int i = 0; i < list.size(); i++) {
			Object detailBean = list.get(i);
			Object newDeailEntity = new Object();
			newDeailEntity = BeanUtils.cloneBean(detailBean);

			ReflectUtil.setFieldValue(newDeailEntity, "fkId", String.class, newId);
			ReflectUtil.setFieldValue(newDeailEntity, "id", String.class, null);
			super.save(newDeailEntity);
		}
	}

}
